// 在Vue数据双向绑定的实现逻辑里，有这样三个关键角色：

// 1.observer（监听器）：注意，此 observer 非彼 observer。
// 在我们上节的解析中，observer 作为设计模式中的一个角色，代表“订阅者”。
// 但在Vue数据双向绑定的角色结构里，所谓的 observer 不仅是一个数据监听器
// 它还需要对监听到的数据进行转发——也就是说它同时还是一个发布者。

// 2.watcher（订阅者）：observer 把数据转发给了真正的订阅者——watcher对象。
// watcher 接收到新的数据后，会去更新视图。

// 3.compile（编译器）：MVVM 框架特有的角色，负责对每个节点元素指令进行扫描和解析
// 指令的数据初始化、订阅者的创建这些“杂活”也归它管~

// 逻辑实现
// 1.实现observer
function observer(target) {
  // 若target是一个对象，则遍历它
  if (target && typeof target === "object") {
    Object.keys(target).forEach((key) => {
      // defineReactive方法会给目标属性装上“监听器”
      defineReactive(target, key, target[key]);
    });
  }
}

// 2.监听器
function defineReactive(target, key, val) {
  const dep = new Dep();

  // 属性值也可能是object类型，这种情况下需要调用observe进行递归遍历
  observer(val);
  Object.defineProperty(target, key, {
    // 可枚举
    enumerable: true,
    // 不可配置
    configurable: false,
    get: function () {
      console.log("有人获取了val");
      dep.depend(new watcher());
      return val;
    },
    // 监听器函数
    set: function (value) {
      // 如果赋值一样 就不操作
      if (target[key] === value) {
        console.log("两次赋值相同RETURN");
        return;
      }
      console.log(`${target}属性的${key}属性从${val}值变成了了${value}`);
      val = value;
      // 通知所有订阅者
      dep.notify();
    },
  });
}
// 监听器创建好后 我们尝试一下
//  const D = {
//    name: '张三'
//  }
//  observer(D)
//  D.name = 1

// 3. 订阅者Dep
class Dep {
  constructor() {
    // 初始化订阅队列
    this.subs = [];
  }

  // 添加订阅者
  depend(sub) {
    console.log("有人调用我===>? ", sub);

    this.subs.push(sub);
  }

  // 通知订阅者
  notify() {
    this.subs.forEach((item) => {
      console.log("更新了");

      item?.update();
    });
  }
}

// 4. 订阅者项目
class watcher {
  constructor(cb) {
    //  回调函数 用于更新
    this._cb = cb;
  }

  update() {
    this._cb();
  }
}

// 监听器创建好后 我们尝试一下
const D = {
  name: "张三",
};
observer(D);
D.name = 1;

// 4.
